#include "app_xf.h"
#include "bsp_ntp.h"

#include <mbedtls/md.h> // 使用 mbedtls 计算 HMAC-SHA256
#include <base64.h>
#include "Base64_Arturo.h"
#include "global_config.h"

using namespace websockets;
extern  WebsocketsClient client;   //WebSocket 客户端




//录音缓存相关的数据结构
int16_t audioData[2560];
int16_t *pcm_data; // 录音缓存区
uint recordingSize = 0;

String g_stt_text = "";//ASR结果
bool g_stt_ste = 0;   //ASR状态：转换成功则为1

// 构造讯飞ws连接url
String XF_wsUrl(const char *Secret, const char *Key, String request, String host)
{
  String timeString = getDateTime();
  String signature_origin = "host: " + host;
  signature_origin += "\n";
  signature_origin += "date: ";
  signature_origin += timeString;
  signature_origin += "\n";
  signature_origin += "GET " + request + " HTTP/1.1";

  // 使用 mbedtls 计算 HMAC-SHA256
  unsigned char hmacResult[32]; // SHA256 产生的哈希结果长度为 32 字节
  mbedtls_md_context_t ctx;
  mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
  mbedtls_md_init(&ctx);
  mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1); // 1 表示 HMAC
  mbedtls_md_hmac_starts(&ctx, (const unsigned char *)Secret, strlen(Secret));
  mbedtls_md_hmac_update(&ctx, (const unsigned char *)signature_origin.c_str(), signature_origin.length());
  mbedtls_md_hmac_finish(&ctx, hmacResult);
  mbedtls_md_free(&ctx);
  // 对结果进行 Base64 编码
  String base64Result = base64::encode(hmacResult, 32);

  String authorization_origin = "api_key=\"";
  authorization_origin += Key;
  authorization_origin += "\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"";
  authorization_origin += base64Result;
  authorization_origin += "\"";
  String authorization = base64::encode(authorization_origin);

  String url = "ws://" + host + request;
  url += "?authorization=";
  url += authorization;
  url += "&date=";
  url += formatDateForURL(timeString);
  url += "&host=" + host;
  return url;
}


void status0_send(int i, uint8_t & status, int dataSize)
{
      String input = "{";
      input += "\"common\":{ \"app_id\":\"" + STTAPPID + "\" },";
      input += "\"business\":{\"domain\": \"iat\", \"language\": \"zh_cn\", \"accent\": \"mandarin\", \"vinfo\":1,\"vad_eos\":10000},";
      input += "\"data\":{\"status\": 0, \"format\": \"audio/L16;rate=16000\",\"encoding\": \"raw\",\"audio\":\"";
      String base64audioString = base64::encode((uint8_t *)pcm_data, dataSize);
      input += base64audioString;
      input += "\"}}";
      Serial.printf("input: %d , status: %d \n", i, status);
      client.send(input);
      status = 1;
}


void status1_send(int i, uint8_t & status, int dataSize) 
{
    String input = "{";
    input += "\"data\":{\"status\": 1, \"format\": \"audio/L16;rate=16000\",\"encoding\": \"raw\",\"audio\":\"";
    String base64audioString = 
        base64::encode(
          (uint8_t *)pcm_data + (i * dataSize), 
          dataSize);
    input += base64audioString;
    input += "\"}}";
    
    // Serial.printf("input: %d , status: %d \n", i, status);
    client.send(input);
}


void status2_send(int i, uint8_t & status, int dataSize, uint lan_end) 
{
  String input = "{";
  input += "\"data\":{\"status\": 2, \"format\": \"audio/L16;rate=16000\",\"encoding\": \"raw\",\"audio\":\"";

  // 根据 lan_end 的值决定编码的数据长度
  int encodeSize = (lan_end == 0) ? dataSize : lan_end;//关键代码
  String base64audioString = 
      base64::encode(
        (uint8_t *)pcm_data + (i * dataSize), 
        encodeSize);

  input += base64audioString;
  input += "\"}}";
  Serial.printf("input: %d , status: %d \n", i, status);
  client.send(input);
}

// 向讯飞STT发送音频数据
void STTsend()
{
  uint8_t status = 0;
  int dataSize = 1280 * 8;//换算成bit?
  //int dataSize = 1280; //此处，不做乘法也行，但是弄成8更快一点

  int audioDataSize = recordingSize * 2;  //总计采集到的音频的字节数（3s）
  //recordingSize 是3s时间采集到的帧的个数，一帧为2B（单声道，16bit深度）



  //计算要分包的次数
  uint lan = (audioDataSize) / dataSize;
  uint lan_end = (audioDataSize) % dataSize;
  if (lan_end > 0)
  {
    lan++;
  }

  // Serial.printf("byteDatasize: %d , lan: %d , lan_end: %d \n", audioDataSize, lan, lan_end);
  String host_url = XF_wsUrl(STTAPISecret, STTAPIKey, "/v2/iat", "ws-api.xfyun.cn");
  Serial.println("Connecting to server.");
  bool connected = client.connect(host_url);
  if (connected)
  {
    Serial.println("Connected!");
  }
  else
  {
    Serial.println("Not Connected!");
  }
  // 分段向STT发送PCM音频数据
  for (int i = 0; i < lan; i++)
  {
    if (i == (lan - 1)) //如果是发送最后一部分了
    {
      status = 2;
    }
    if (status == 0) //如果发送的是第一包
    {
      status0_send(i, status, dataSize);
    }
    else if (status == 1)//如果发送的是中间的包
    {
      status1_send(i, status, dataSize);
    }
    else if (status == 2)
    {
      status2_send(i, status, dataSize, lan_end);
    }
    delay(30);
  }
}

/**
 * @brief WebSocket客户端的回调函数
 * 
 * @param message 
 */
void handleWebSocketMessage(WebsocketsMessage message) 
{
    // STT ws连接的回调函数
    Serial.print("Got Message: ");
    Serial.println(message.data());
    JsonDocument doc;
    DeserializationError error = deserializeJson(doc, message.data());
    if (error)
    {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.f_str());
      return;
    }
    JsonArray ws = doc["data"]["result"]["ws"];
    for (JsonObject word : ws)
    {
      int bg = word["bg"];
      const char *w = word["cw"][0]["w"];
      g_stt_text += w;
    }
    if (doc["data"]["status"] == 2)
    {
       // 收到结束标志
      g_stt_ste = 1;
      Serial.print("语音识别：");
      Serial.println(g_stt_text);
    }
}